package cn.ant.service.custom;

import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.BpmnAutoLayout;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.impl.cmd.AbstractDynamicInjectionCmd;
import org.flowable.engine.impl.context.Context;
import org.flowable.engine.impl.dynamic.DynamicUserTaskBuilder;
import org.flowable.engine.impl.persistence.entity.DeploymentEntity;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager;
import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.springframework.beans.BeanUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * @Version 1.0
 * @Author:lss
 * @Date:2021/10/26
 * @Content: 动态新增任务节点(不包含子流程)
 */
@Slf4j
public class CustomSimpleSerialUserTask extends AbstractDynamicInjectionCmd implements Command<Void> {

    //需要动态添加的新节点
    private DynamicUserTaskBuilder dynamicUserTaskBuilder;
    //新节点动态添加到的流程实例Id
    private String processInstanceId;
    //在流程中的哪一个节点后面添加新节点
    private FlowElement currentFlowElement;


    public CustomSimpleSerialUserTask(String processInstanceId, FlowElement currentFlowElement, DynamicUserTaskBuilder dynamicUserTaskBuilder) {
        this.processInstanceId = processInstanceId;
        this.currentFlowElement = currentFlowElement;
        this.dynamicUserTaskBuilder = dynamicUserTaskBuilder;
    }

    @Override
    protected void updateBpmnProcess(CommandContext commandContext, Process process, BpmnModel bpmnModel, ProcessDefinitionEntity processDefinitionEntity, DeploymentEntity deploymentEntity) {
        log.info("updateBpmnProcess.start");
        /**将当前节点的数据复制到一个新对象 然后将id或taskId以及代理人，任务名字需要改*/
        UserTask newUserTask = new UserTask();
        //复制一个节点，除id或taskId等关键信息不一致，其他公共信息一致
        BeanUtils.copyProperties(this.currentFlowElement, newUserTask);
        //设置taskId
        if (this.dynamicUserTaskBuilder.getId() != null) {
            newUserTask.setId(this.dynamicUserTaskBuilder.getId());//自定义taskId
        } else {
            newUserTask.setId(this.dynamicUserTaskBuilder.nextTaskId(process.getFlowElementMap()));//整个流程的最后的一个taskId后面追加一个taskId
        }
        this.dynamicUserTaskBuilder.setDynamicTaskId(newUserTask.getId());
        newUserTask.setAssignee(this.dynamicUserTaskBuilder.getAssignee());
        newUserTask.setName(this.dynamicUserTaskBuilder.getName());
        /**将当前节点强制转换*/
        UserTask currentTask = (UserTask) this.currentFlowElement;
        //顺序线
        SequenceFlow sequenceFlow = null;
        //构建新节点的出线集合
        List<SequenceFlow> outgoingFlows = new ArrayList<>();
        //当前节点已关联的出现集合
        List<SequenceFlow> sequenceFlowList = currentTask.getOutgoingFlows();
        log.info("sequenceFlowList ===> {}", sequenceFlowList);
        log.info("sequenceFlowList.size ===> {}", sequenceFlowList.size());
        for (int i = 0; i < sequenceFlowList.size(); i++) {
            SequenceFlow outgoingFlow = sequenceFlowList.get(i);
            //创建一条新的顺序流(下面参数表示当前顺序流的前面关联一个任务，后面连接另外一个目标的引用)
            SequenceFlow newSequenceFlow = new SequenceFlow(newUserTask.getId(), outgoingFlow.getTargetRef());
            newSequenceFlow.setSkipExpression(outgoingFlow.getSkipExpression());
            newSequenceFlow.setConditionExpression(outgoingFlow.getConditionExpression());
            newSequenceFlow.setExtensionElements(outgoingFlow.getExtensionElements());
            newSequenceFlow.setExecutionListeners(outgoingFlow.getExecutionListeners());
            newSequenceFlow.setName(outgoingFlow.getName());
            newSequenceFlow.setId("newSid-" + UUID.randomUUID().toString());
            //添加到集合
            outgoingFlows.add(outgoingFlow);
            //删除原先节点的出线
            process.removeFlowElement(outgoingFlow.getId());
            //将新构建好的出线整合到流程(新构建好的出线前面目标是连接新节点的，后面是连接主流程的)
            process.addFlowElement(newSequenceFlow);
        }
        log.info("outgoingFlows ===> {}", outgoingFlows);
        log.info("outgoingFlows.size ===> {}", outgoingFlows.size());
        /**新节点的入线集合*/
        List<SequenceFlow> incomingFlows = new ArrayList<>();
        //构建一条新的入线（参数是将当前节点与新节点进行关联）
        SequenceFlow newIncomingFlow = new SequenceFlow(currentTask.getId(), newUserTask.getId());
        newIncomingFlow.setId("newSid-" + UUID.randomUUID().toString());
        incomingFlows.add(newIncomingFlow);
        log.info("incomingFlows ===> {}", incomingFlows);
        log.info("incomingFlows.size ===> {}", incomingFlows.size());
        //将新构建好的入线整合到流程
        process.addFlowElement(newIncomingFlow);
        //将新节点整合到流程
        process.addFlowElement(newUserTask);
        /**自定义坐标：无*/
        new BpmnAutoLayout(bpmnModel).execute();
        log.info("updateBpmnProcess.end");
    }

    @Override
    protected void updateExecutions(CommandContext commandContext, ProcessDefinitionEntity processDefinitionEntity, ExecutionEntity executionEntity, List<ExecutionEntity> list) {
        log.info("updateExecutions.start");
        log.info("updateExecutions.end");
    }

    @Override
    public Void execute(CommandContext commandContext) {
        createDerivedProcessDefinitionForProcessInstance(commandContext, processInstanceId);
        return null;
    }
}

